import treemap.*;
import controlP5.*;
//Adding the ControlP5 library

ControlP5 controlP5;//declaring the controlp5 library variable.

MovieTable data;
int[][] yearTotals;
int[][] yearIndex;
int mostInOneYear = 0;
boolean inclusive = true;
boolean compareAgainstTotals = true;
int[] myPicks;

float mapWidth;
float mapHeight;
float mapGraphCornerX;
float mapGraphCornerY;

//variables for window height and width needed for widgets
int windowHeight, windowWidth;
//  buttonSelRange, buttonSelYear,
Controller buttonYears, buttonDecades, buttonMonths, buttonSeasons, buttonAverage, buttonTotal, buttonAbs, buttonPer;
ListBox l1, l2, l3;

 //globals for the time slider
myDoubleSlider slider;
float sliderX1, sliderY1;
float sliderX2, sliderY2;

//globals for cluster mode
int clusterMode;
int yearsMode = 1;
int decadesMode = 2;
int monthsMode = 3;
int seasonsMode = 4;
int lastMode;

//globals for selection mode

int selectionMode;
int rangeMode = 1;
int yearMode = 2;

//globals for stack view
int stackMode;
int absMode = 1;
int perMode = 2;

//globals for average and total
boolean showTotal, showAverage;
boolean checkAll;


//checkboxes for selecting genre's
CheckBoxes genreSelectBox;
float genreSelectBoxX1, genreSelectBoxY1;
float genreSelectBoxX2, genreSelectBoxY2;
boolean genreSelected[];
int genreColors[];


////------------CODE FOR TREEMAP-------------//////////////////
///// declaring variables to use in TREEMAP
BoundsIntegrator zoomBounds;
WordItem rolloverItem;

MapGraph mGraph;
boolean drawTree = false;
/////--------------------------////////////////



void setup()
{
  size(1024, 768);
  
  windowHeight = 768;
  windowWidth = 1024;
  
  mapWidth = windowWidth - 110;
  mapHeight = windowHeight - 188;
  mapGraphCornerX = 0;
  mapGraphCornerY = windowHeight - 660;


  data = new MovieTable("finaltable.txt");

  selectedGenreInfo = new int[genres.length][];
  ///----------------CODE FOR TREEMAP-------------------///////
  mGraph = new MapGraph();
  mGraph.setup();

  //////////-----------------------------------/////////////////
  yearTotals = totalsPerYear();

  for( int i = 0; i < yearTotals.length; i++)
  {
    int tempN = 0;
    for( int j = 0; j < 13; j++)
    {
      tempN += yearTotals[i][j];
    }
    if( tempN > mostInOneYear)
    {
      mostInOneYear = tempN;
    }
  }

  

  //  println(mostInOneYear);
  
  //Setup for widgets and gui
  //setup for slider values
  sliderX1 = 10;
  sliderY1 = windowHeight - 70;//height-400;
  sliderX2 = windowWidth-120;
  sliderY2 = windowHeight - 5;//height-350;
  slider = new myDoubleSlider(sliderX1, sliderY1, sliderX2, sliderY2, 1920, 2009, 5, 1);

  
  int numOfCategories = 18; 
  
  //initializing the checkboxes
  String[] boxLabels = new String[numOfCategories];
  //boxLabels[0] = "0.0\n-\n1.9";
  boxLabels[0] = "Action";
  boxLabels[1] = "Adventure";
  boxLabels[2] = "Animation";
  boxLabels[3] = "Comedy";
  boxLabels[4] = "Crime";
  boxLabels[5] = "Documentary";
  boxLabels[6] = "Drama";
  boxLabels[7] = "Family";
  boxLabels[8] = "Fantasy";
  boxLabels[9] = "Film-Noir";
  boxLabels[10] = "Horror";
  boxLabels[11] = "Musical";
  boxLabels[12] = "Mystery";
  boxLabels[13] = "Romance";
  boxLabels[14] = "Sci-Fi";
  boxLabels[15] = "Thriller";
  boxLabels[16] = "War";
  boxLabels[17] = "Western";
  
  genreColors = new int[numOfCategories];
  genreColors[0] = 0xFF030D87;
  genreColors[1] = 0xFF703032;
  genreColors[2] = 0xFFFB6A4A;
  genreColors[3] = 0xFF4B9694;
  genreColors[4] = 0xFFEF3B2C;
  genreColors[5] = 0xFFCB181D;
  genreColors[6] = 0xFF787878;
  genreColors[7] = 0xFF979EFD; 
  genreColors[8] = 0xFF1D653E;
  genreColors[9] = 0xFF4E1252;
  genreColors[10] = 0xFFFC9272;
  genreColors[11] = 0xFF2838FB;
  genreColors[12] = 0xFFEF3B2C;
  genreColors[13] = 0xFFCB8789;
  genreColors[14] = 0xFF336463;
  genreColors[15] = 0xFFAC28B7; 
  genreColors[16] = 0xFF99000D;
  genreColors[17] = 0xFFAE4A4D;

  genreSelected = new boolean[numOfCategories];
  for(int i = 0; i < genreSelected.length; i++){
    
    genreSelected[i] = true;
  }
  
  genreSelectBoxX2 = width;
  genreSelectBoxX1 = genreSelectBoxX2-110;
  genreSelectBoxY1 = windowHeight-644;
  genreSelectBoxY2 = genreSelectBoxY1 + 580;
 
  genreSelectBox = new CheckBoxes(numOfCategories, "Genre", boxLabels, genreSelectBoxX1, genreSelectBoxY1, genreSelectBoxX2, genreSelectBoxY2, genreColors);
  
  myPicks = getGenres();
  clusterMode = yearsMode;
  lastMode = yearsMode;

  for( int j = 0; j < myPicks.length; j++)
  {
    selectedGenreInfo[myPicks[j]] = findData( genres[myPicks[j]]);
  }
 

  //declaring the function for adding the controlp5 buttons.
   controlP5 = new ControlP5(this); //Creating an instance of the button library variable in setup
  addControlButtons ();
}

void draw()
{
  background(0);
  
   //drawing backgrounds for the upper and lower menu regions
  rectMode(CORNER);
  fill(50);
  rect(0, 0, windowWidth, windowHeight-660);
  rect(0, windowHeight-80, windowWidth, 80);
  
  mGraph.calculateIndex();
  
  
  
  //drawing checkboxes
  genreSelectBox.drawCheckBoxes();
  
//  for(int i = 0; i < genreSelected.length; i++){
//    if(checkAll)
//    {
//      genreSelected[i] = true;
//      resetgenreSel(i);
//    }
//    else
//    {
//      genreSelected[i] = false;
//      resetgenreSel(i);
//    }
//  }
 
  
  //drawing the time slider
  slider.drawSlider();
  /////////--------Bunch of code for labels all over the GUI-------/////////////////////////
   //Drawing label for time selection buttons
   stroke(0);
   line(0,windowHeight - 80,windowWidth,windowHeight - 80);
   line(windowWidth-102, windowHeight-80, windowWidth-102, windowHeight);
//   fill(255);
//  textAlign(CENTER);
//  textSize(12);
//  text("Time Selection", windowWidth-40, windowHeight-65);
  
  //Drawing partition lines for menu's at the top
  stroke(0);
    line(windowWidth-600, 0, windowWidth-600, windowHeight-660);
    line(windowWidth-500, 0, windowWidth-500, windowHeight-660);
    line(windowWidth-250, 0, windowWidth-250, windowHeight-660);
    line(0, windowHeight-678, windowWidth-600, windowHeight-678);
     fill(255);
  textAlign(CENTER);
  textSize(12);
  text("Clustering Option", windowWidth-830, windowHeight-755);
  text("Most Popular", windowWidth-375, windowHeight-755);
  text("Highest Rated", windowWidth-125, windowHeight-755);
  text("Compare", windowWidth-550, windowHeight-755);
  text("Select View", windowWidth-924, windowHeight-666);
  //////////----------------//////////////////////////

  noStroke();
  fill( 255, 240);
  rect( mapGraphCornerX, mapGraphCornerY, mapWidth, mapHeight);

  
  //  if( compareAgainstTotals)
  //  {
  //    drawFullRangeAll();
  //  }

  //  if( inclusive)
  //  {
  //    stroke( 98, 198, 100);
  //    drawFullRange("Comedy");
  //    stroke( 86, 164, 209);
  //    drawFullRange("Animation");
  //  }
  //  else
  //  {
  //    stroke( 254, 22, 28);
  //    drawFullRange( "Comedy", "Animation");
  //  }
  ///////-------------CODE MODIFIED FOR TREEMAP----////////
  //// THIS part toggles between stack and treemap view
  if(drawTree)
  {
    stroke(1);
    fill(155,240,100);
    mGraph.draw();
  }  
  else
  {
    //Draw line graphs
    drawStackPlot( myPicks);
  }  
  //////------------------------------------------///////
  //end line graphs
  smooth();
}

void keyReleased()
{
  mGraph.keyReleased();
  if(key == 'i' || key == 'I')
  {
    inclusive = !inclusive;
  }
  ////////////-------CODE FOR TREEMAP-----////////
  /////PRESS T to toggle between treemap and stack view//
  if(key == 'T' || key == 't')
  {
    drawTree = !drawTree;
  }
  ///////////////-------------------------////////
}


 void resetgenreSel(int catToChange){
    genreSelected[ catToChange ] = !genreSelected[ catToChange ];
  }
  
//  
void mouseDragged() {
  
if( mouseY > sliderY1 - 20 && mouseY < sliderY2 + 20 ){//is approx over slider bar
       //see if sliders are exactly over each other, then move in tandem
       if( abs( slider.getSlider2Position() - slider.getSlider1Position()) <= 10 ){
        if( mouseX > slider.getSlider2Position()-slider.getSliderSize()/2 - 50 && mouseX < slider.getSlider2Position() + slider.getSliderSize()/2 +50 ){
          slider.setSlider2Position(mouseX);
          
          rangeYears[1] =  slider.getYear( slider.getSlider2Position() );
          
          slider.setSlider1Position(mouseX);
          
          rangeYears[0] =  slider.getYear( slider.getSlider1Position() );
          
         
        }  
       }
       // see if it is exactly over slider 1
      else if( mouseX > slider.getSlider1Position()-slider.getSliderSize()/2 && mouseX < slider.getSlider1Position() + slider.getSliderSize()/2 ){//is over slider 1 
         slider.setSlider1Position(mouseX); 
         
         rangeYears[0] =  slider.getYear( slider.getSlider1Position() );
         
      }//then see if it is exactly over slider 2
      else if( mouseX > slider.getSlider2Position() - slider.getSliderSize()/2 && mouseX < slider.getSlider2Position() + slider.getSliderSize()/2 ){//is over slider 2
        slider.setSlider2Position(mouseX);
        
        rangeYears[1] =  slider.getYear( slider.getSlider2Position() );    
        
        
      }
      //then see if it is approx over slider 1
      else if( mouseX > slider.getSlider1Position()-slider.getSliderSize()/2 - 50 && mouseX < slider.getSlider1Position() + slider.getSliderSize()/2 + 50 ){//is approx over slider 1
          slider.setSlider1Position(mouseX); 
          
          rangeYears[0] =  slider.getYear( slider.getSlider1Position() );
          
      }//finally, see if it is approx over slider 2
      else if( mouseX > slider.getSlider2Position() - slider.getSliderSize()/2 - 50 && mouseX < slider.getSlider2Position() + slider.getSliderSize()/2 + 50 ){//is approx over slider 2
        slider.setSlider2Position(mouseX);     
        
        rangeYears[1] =  slider.getYear( slider.getSlider2Position() );    
        
      }
    }
  }//end over slider

void mouseMoved() {
  mGraph.mouseMoved();
}

void mousePressed() {
  
 if( mouseX > sliderX1 && mouseX < sliderX2 && mouseY > sliderY1 && mouseY < sliderY2 ){//is over slider
    float slider1Position = slider.getSlider1Position();
    float slider2Position = slider.getSlider2Position();
    
    if( mouseX < slider1Position ){      
      slider.setSlider1Position(mouseX); 
    
      rangeYears[0] =  slider.getYear( slider.getSlider1Position() );
      
     }
    else if( mouseX > slider2Position ){
      slider.setSlider2Position(mouseX);     

      rangeYears[1] =  slider.getYear( slider.getSlider2Position() );    
     
    }
    else if( mouseX - slider1Position < slider2Position - mouseX ){ //if closer to slider 1
      slider.setSlider1Position(mouseX); 
      
      rangeYears[0] =  slider.getYear( slider.getSlider1Position() );
      
    }
    else {
      slider.setSlider2Position(mouseX); 
     
      rangeYears[1] =  slider.getYear( slider.getSlider2Position() );    
      
  }
  }//end over slider
 //--------genre box checked or unchecked
  boolean[] returned = genreSelectBox.isChecked(mouseX, mouseY);
  
  for(int i = 0; i< genreSelected.length; i++){
    //println( "i " + i + " magSelected[i] = " + magSelected[i] + " returned[i] = " + returned[i]);
    if( genreSelected[i] != returned[i] ){//new magnitude values
      //determine what is different
      //println("new value " + i);
      if( genreSelected[i] && !returned[i] ){ //remove a category
          //println("remove " + i);
          
          resetgenreSel(i);
//          selectedGenreInfo[i] = null;
      } else if( !genreSelected[i] && returned[i] ){ //sanity check
            
           resetgenreSel(i);
//           selectedGenreInfo[i] = findData(genres[i]);
      }
    }//end sth is diff
  }//end for loop
  //println( "after returned ");
  for(int i = 0; i< genreSelected.length; i++){
    genreSelected[i] = returned[i];
//    selectedGenreInfo[i] = findData(genres[i]);
    //println( "i " + i + " magSelected[i] = " + magSelected[i] + " returned[i] = " + returned[i]);
  }
  
  myPicks = getGenres();
  if( myPicks.length != 1)
  {
    showAverage = false;
    toggleButton(buttonAverage, false);
  }
  if( myPicks.length > 1)
  {
    showTotal = false;
    toggleButton(buttonTotal, false);
  }
  
}

void addControlButtons() {
  
  controlP5.setColorBackground(color(150));
  controlP5.setColorActive(color(0));
  buttonYears = controlP5.addButton("Years", 100, windowWidth - 1000, windowHeight-748, 80, 15);
  buttonDecades = controlP5.addButton("Decades", 200, windowWidth - 900, windowHeight-748, 80, 15);
  buttonMonths = controlP5.addButton("Months", 300, windowWidth - 800, windowHeight-748, 80, 15);
  buttonSeasons = controlP5.addButton("Seasons", 400, windowWidth - 700, windowHeight-748, 80, 15);
  
    
 
  
//  buttonSelRange = controlP5.addButton("Check All", 1000, windowWidth - 80, windowHeight-60, 80, 15);
//  buttonSelYear = controlP5.addButton("Uncheck All", 2000, windowWidth - 80, windowHeight-40, 80, 15);
  
  //Compare buttons
  buttonTotal = controlP5.addButton("Total", 500, windowWidth - 590, windowHeight-720, 80, 15);
  buttonAverage = controlP5.addButton("Average", 600, windowWidth - 590, windowHeight-700, 80, 15);
  
  //buttons for absolute and percentage views
  buttonAbs = controlP5.addButton("Stack View", 700, windowWidth - 824, windowHeight-677, 112, 17);
  buttonPer = controlP5.addButton("Treemap View", 800, windowWidth - 712, windowHeight-677, 112, 17);
  
  buttonYears.setId(100);
  buttonDecades.setId(200);
  buttonMonths.setId(300);
  buttonSeasons.setId(400);
//  buttonSelRange.setId(1000);
//  buttonSelYear.setId(2000);
  buttonTotal.setId(500);
  buttonAverage.setId(600);
  buttonAbs.setId(700);
  buttonPer.setId(800);
  
  
  
 //println("what the hell");
  
  
  toggleButton(buttonYears, true);
  toggleButton(buttonDecades, false);
  toggleButton(buttonMonths, false);
  toggleButton(buttonSeasons, false);    
  
  
//toggleButton(buttonSelRange, false);
//toggleButton(buttonSelYear, false);

toggleButton(buttonTotal, false);
toggleButton(buttonAverage, false);

toggleButton(buttonAbs, true);
toggleButton(buttonPer, false);


//initializing average and total buttons
showTotal = false;
showAverage = false;



//code for the list boxes in the cluster menu

l1 = controlP5.addListBox("decadeList",windowWidth-900,windowHeight-708,80,30);
//controlP5.Listbox.actAsPulldownMenu(true);
  l1.setItemHeight(15);
  l1.setBarHeight(15);
 // l1.setColorActive( color(0) );
  l1.setColorForeground(color (0) );
  l1.captionLabel().toUpperCase(true);
  
  l1.captionLabel().set("Select Decade");
  l1.captionLabel().style().marginTop = 3;
  l1.valueLabel().style().marginTop = 3; // the +/- sign
  //l.setBackgroundColor(color(100,0,0));
  
    l1.addItem("1920",21);
    l1.addItem("1930",22);
    l1.addItem("1940",23);
    l1.addItem("1950",24);
    l1.addItem("1960",25);
    l1.addItem("1970",26);
    l1.addItem("1980",27);
    l1.addItem("1990",28);
    l1.addItem("2000",29);
    l1.addItem("2010",30);
    l1.hide();
  
  
  
l2 = controlP5.addListBox("monthList",windowWidth-800,windowHeight-708,80,30);
  l2.setItemHeight(15);
  l2.setBarHeight(15);
  l2.setColorForeground(color (0) );
  l2.captionLabel().toUpperCase(true);
 // l2.captionLabel().setColorActive( color(0) );
  l2.captionLabel().set("Select Month");
  l2.captionLabel().style().marginTop = 3;
  l2.valueLabel().style().marginTop = 3; // the +/- sign
  //l.setBackgroundColor(color(100,0,0));
 
    l2.addItem("January",0);
  l2.addItem("February",1);
  l2.addItem("March",2);
  l2.addItem("April",3);
  l2.addItem("May",4);
  l2.addItem("June",5);
  l2.addItem("July",6);
  l2.addItem("August",7);
  l2.addItem("September",8);
  l2.addItem("October",9);
  l2.addItem("November",10);
  l2.addItem("December",11);
  l2.hide();
  
l3 = controlP5.addListBox("seasonList",windowWidth-700,windowHeight-708,80,30);
  l3.setItemHeight(15);
  l3.setBarHeight(15);
  l3.setColorForeground(color (0) );
  l3.captionLabel().toUpperCase(true);
  //l3.captionLabel().setColorActive( color(0) );
  l3.captionLabel().set("Select Season");
  l3.captionLabel().style().marginTop = 3;
  l3.valueLabel().style().marginTop = 3; // the +/- sign
  //l.setBackgroundColor(color(100,0,0));
  
  l3.addItem("Spring",12);
  l3.addItem("Summer",13);
  l3.addItem("Fall",14);
  l3.addItem("Winter",15);
  l3.hide();
  
}

void toggleButton(Controller theController, boolean buttonEnabled) {
  if( buttonEnabled ) {
    theController.setColorBackground( color(0) );
    theController.setColorLabel( color(255) ); 
    theController.setColorActive( color(0) );
  }
  else {
    theController.setColorBackground(color(150,125));
    theController.setColorLabel( color(255) ); 
    theController.setColorActive( color(0) );
  }
}


void controlEvent(ControlEvent theEvent) {
  //println("got click from " + theEvent.controller().name());
  
  if( theEvent.isGroup())
  {
    if( theEvent.group().value() < 12)
    {
//      clusterMode = monthsMode;
      if( theEvent.group().value() != selectedMonth)
      {
        selectedMonth = int(theEvent.group().value());
        for( int i = 0; i < selectedGenreInfo.length; i++)
        {
          selectedGenreInfo[i] = findData(genres[i]);
        }
        if( showAverage )
        {
          theAverage = findAverage(myPicks[0]);
        }
      }
    }
    else if( theEvent.group().value() < 20)
    {
      if( theEvent.group().value() != selectedSeason)
      {
        selectedSeason = int(theEvent.group().value()) - 12;
        for( int i = 0; i < selectedGenreInfo.length; i++)
        {
          selectedGenreInfo[i] = findData(genres[i]);
        }
        if( showAverage )
        {
          theAverage = findAverage(myPicks[0]);
        }
      }
    }
  }
  
   
  
  
  switch( theEvent.controller().id() ) {
      
    case 100:
      lastMode = clusterMode;
      clusterMode = yearsMode;
      
      
  l1.hide();
  l2.hide();
  l3.hide();
      toggleButton(buttonYears, true);
  toggleButton(buttonDecades, false);
  toggleButton(buttonMonths, false);
  toggleButton(buttonSeasons, false);
  
  
      break;
      
      
    case 200:
      
      lastMode = clusterMode;
      clusterMode = decadesMode;
      l1.show();
  l2.hide();
  l3.hide();
  
      toggleButton(buttonYears, false);
  toggleButton(buttonDecades, true);
  toggleButton(buttonMonths, false);
  toggleButton(buttonSeasons, false);
      break;
      
    case 300:
      lastMode = clusterMode;
      clusterMode = monthsMode;
      l1.hide();
  l2.show();
  l3.hide();
  
      toggleButton(buttonYears, false);
  toggleButton(buttonDecades, false);
  toggleButton(buttonMonths, true);
  toggleButton(buttonSeasons, false);
      break;
      
    case 400:
      lastMode = clusterMode;
      clusterMode = seasonsMode;
      l1.hide();
  l2.hide();
  l3.show();
      toggleButton(buttonYears, false);
  toggleButton(buttonDecades, false);
  toggleButton(buttonMonths, false);
  toggleButton(buttonSeasons, true);
      break;   
    
    case 500:
    if( myPicks.length < 2)
    {
      showTotal = !showTotal;
    }
    if(showTotal)
    toggleButton(buttonTotal, true);
    else
    toggleButton(buttonTotal, false);
    break;
    
    case 600:
    if( myPicks.length == 1)
    {
      showAverage = !showAverage;
      theAverage = findAverage(myPicks[0]);
    }
    if(showAverage)
    toggleButton(buttonAverage, true);
    else
    toggleButton(buttonAverage, false);
    
    
    break;
    
    case 700:
    stackMode = absMode;
    drawTree = false;
    toggleButton(buttonAbs, true);
    
    toggleButton(buttonPer, false);
    break;
    
    case 800:
    stackMode = perMode;
    drawTree = true;
    toggleButton(buttonAbs, false);
    
    toggleButton(buttonPer, true);
    break;
      
//     case 1000:
//      checkAll = true;
//      
//     // toggleButton(buttonSelRange, checkAll);
//  //toggleButton(buttonSelYear, false);
//      break; 
//      
//    case 2000:
//      checkAll = false;
//  
////      toggleButton(buttonSelRange, false);
////  toggleButton(buttonSelYear, true);
//      break;     
      
    default:
     println("deafault settings");
      break;
  }
  
  if(lastMode != clusterMode)
  {
    for( int i = 0; i < selectedGenreInfo.length; i++)
    {
      selectedGenreInfo[i] = findData(genres[i]);
    }
    if( showAverage )
    {
      theAverage = findAverage(myPicks[0]);
    }
  }
 
}
  
int[] getGenres()
{
  int numOfGenres = 0;
  for( int i = 0; i < genreSelected.length; i++)
  {
    if(genreSelected[i])
    {
      numOfGenres++;
    }
  }
  
  int [] theGenres = new int [numOfGenres];
  int temp = 0;
  for( int j = 0; j < genreSelected.length; j++)
  {
    if(genreSelected[j])
    {
      theGenres[temp] = j;
      temp++;
    }
  }
  return theGenres;
}

